package com.weishao.learn;

import javax.tools.JavaCompiler;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

/**
 * java 动态编译。
 * 
 * 说明：tools.jar并不在jre中，而是在jdk安装目录下，因此需要手动
 *             把这个jar文件从jdk目录下拷贝到了jre目录下，再次运行
 */
public class TrendsJava {

	public static void main(String[] args) {
		int i = 10;
		String code = "System.out.println(\"Hello World!\"+(13+2*5/3));";
		code += "for(int i=0;i<" + i + ";i++){";
		code += " System.out.println(Math.pow(i,2));";
		code += "}";
		try {
			run(code);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private synchronized static File compile(String code) throws Exception {
		File file = File.createTempFile("JavaRuntime", ".java", new File(Constants.BASEDIR));
		file.deleteOnExit();
		// 获得类名
		String classname = getBaseFileName(file);
		// 将代码输出到文件
		PrintWriter out = new PrintWriter(new FileOutputStream(file));
		out.println(getClassCode(code, classname));
		out.close();

		// 编译生成的java文件
		String[] cpargs = new String[] { "-d", Constants.BASEDIR, file.getName() };

		System.out.println(System.getProperty("user.dir"));
		
		// 动态编译
		JavaCompiler javac = ToolProvider.getSystemJavaCompiler();
		int status = javac.run(null, null, null, "-d", Constants.BASEDIR, Constants.BASEDIR + file.getName());
		if (status != 0) {
			throw new Exception("语法错误！");
		}
		return file;
	}

	private static synchronized void run(String code) throws Exception {
		String classname = getBaseFileName(compile(code));
		new File(Constants.BASEDIR + classname + Constants.SUFFIX).deleteOnExit();
		try {
			MyClassLoader loader = new MyClassLoader();

			Class cls = loader.findClass(classname);
			Method main = cls.getMethod("method", null);
			main.invoke(cls, null);
		} catch (Exception se) {
			se.printStackTrace();
		}
	}

	// 将一块代码封装到 method函数中
	private static String getClassCode(String code, String className) {
		StringBuffer text = new StringBuffer();
		text.append("public class " + className + "{\n");
		text.append(" public static void method(){\n");
		text.append(" " + code + "\n");
		text.append(" }\n");
		text.append("}");
		return text.toString();
	}

	private static String getBaseFileName(File file) {
		String fileName = file.getName();
		if (fileName.contains(".")) {
			return fileName.split("\\.")[0];
		} else {
			return fileName;
		}

	}
}

//重写类加载器达到加载指定目录的类
class MyClassLoader extends ClassLoader {

	@Override
	protected Class<?> findClass(String name) {

		String myPath = new File(Constants.BASEDIR + name + Constants.SUFFIX).toURI().toString();
		System.out.println(myPath);
		byte[] cLassBytes = null;
		Path path = null;
		try {
			path = Paths.get(new URI(myPath));
			cLassBytes = Files.readAllBytes(path);
		} catch (IOException | URISyntaxException e) {
			e.printStackTrace();
		}
		Class clazz = defineClass(name, cLassBytes, 0, cLassBytes.length);
		return clazz;
	}

}

//常量
interface Constants {
	String BASEDIR = "E:\\";
	String SUFFIX = ".class";
}
